home *** CD-ROM | disk | FTP | other *** search
/ Aminet 25 / Aminet 25 (1998)(GTI - Schatztruhe)[!][Jun 1998].iso / Aminet / misc / math / ReadWorkSheet.lha / ReadWorkSheet.rexx < prev   
Encoding:
OS/2 REXX Batch file  |  1998-03-04  |  43.6 KB  |  1,209 lines

  1. /* Read a specified Maple WorkSheet, parse it,
  2.  * and feed it to the Maple computation engine
  3.  *
  4.  * Copyright © Joe Veazey 1996
  5.  * Copyright © Thore Böckelmann 1997,1998
  6.  * All rights reserved
  7.  * $VER: ReadWorkSheet.rexx 2.1 (4.3.98)
  8.  *
  9.  * History:
  10.  *  1.0: first release by Joe Veazey
  11.  *  2.0: added support for MapleV R4 worksheets
  12.  *  2.1: fixed problems with R4 worksheets from Intel systems
  13.  *       added support for missing region markers
  14.  *       R4 Hyperlinks (not supported by R3) are now surrounded by "_" and treated as comments
  15.  */
  16.  
  17. options results
  18. options failat 30
  19.  
  20. signal on syntax
  21. signal on novalue
  22.  
  23. LexState.CurrentLine      = ""
  24. LexState.CurrentCol       = 1
  25. LexState.UnGetQueue       = ""
  26. LexState.LineNumber       = 0
  27.  
  28. ParseState.UnGetQueue     = ""
  29. ParseState.UnGetTypeQueue = ""
  30. ParseState.CurrentToken   = ""
  31. ParseState.TokenValue     = ""
  32. ParseState.TokenType      = ""
  33. ParseState.Indent         = 0
  34. ParseState.SemanticText   = ""
  35.  
  36. parse arg FileName " " Options
  37. parse upper value " "Options" ." with " TRACE"      +1 TraceFlag      " "
  38. parse upper value " "Options" ." with " TOKENTRACE" +1 TokenTraceFlag " "
  39. parse upper value " "Options" ." with " PARSETRACE" +1 ParseTraceFlag " "
  40. parse upper value " "Options" ." with " LIST"       +1 LexListFlag " "
  41. parse upper value " "Options" ." with " NOMAPLE"    +1 NoMapleFlag " "
  42. parse upper value " "Options" ." with " ASYNC"      +1 AsyncFlag " "
  43.  
  44. if TraceFlag      ~= "" then trace results
  45.  
  46. if TokenTraceFlag ~= "" ,
  47.   then ParseState.TokenTrace = 1
  48.   else ParseState.TokenTrace = 0
  49.  
  50. if ParseTraceFlag ~= "" ,
  51.   then ParseState.ParseTrace = 1
  52.   else ParseState.ParseTrace = 0
  53.  
  54. if LexListFlag ~= "" ,
  55.   then LexState.List = 1
  56.   else LexState.List = 0
  57.  
  58. if NoMapleFlag ~= "" ,
  59.   then ExecuteState.CallMaple = 0
  60.   else ExecuteState.CallMaple = 1
  61.  
  62. if AsyncFlag ~= "" ,
  63.   then ExecuteState.Async = 1
  64.   else ExecuteState.Async = 0
  65.  
  66. if FileName == "?" | FileName == "" ,
  67.   then do
  68.          say "FORMAT"
  69.          say "     ReadWorkSheet [Filename | ?] [TRACE] [TOKENTRACE] [PARSETRACE]"
  70.          say "                                  [LIST] [NOMAPLE] [ASYNC]"
  71.          say ""
  72.          say "TEMPLATE"
  73.          say "     Filename,TRACE/S,TOKENTRACE/S,PARSETRACE/S,LIST/S,NOMAPLE/S,ASYNC/S"
  74.          say ""
  75.          say "PURPOSE"
  76.          say "     Allow Amiga MapleV R3 to read worksheets produced by other MapleV  versions"
  77.          say "     and platforms"
  78.          say ""
  79.          say "SPECIFICATION"
  80.          say "     ReadWorkSheet.rexx is an ARexx script to read and execute MapleV  worksheet"
  81.          say "     produced  by any platform or MapleV version. Text regions and input regions"
  82.          say "     will be passed to the Amiga MapleV engine to be processed."
  83.          say ""
  84.          say "     The filename can be replaced with ? to obtain this help output."
  85.          say ""
  86.          say "     The TRACE keyword causes an ARexx 'Trace Results' to be issued and is meant"
  87.          say "     for debugging ReadWorkSheet itself."
  88.          say ""
  89.          say "     TOKENTRACE will display each and every token from the worksheet  as  it  is"
  90.          say "     read. Also used for debugging or checking out the syntax of a new worksheet"
  91.          say "     format."
  92.          say ""
  93.          say "     PARSETRACE traces the  entry  and  exit  of  all  parse  subroutines,  with"
  94.          say "     indentation.  Various  significant  data  from  the  worksheet will also be"
  95.          say "     displayed."
  96.          say ""
  97.          say "     LIST will list the contents of the entire worksheet to  STDOUT,  as  it  is"
  98.          say "     parsed."
  99.          say ""
  100.          say "     NOMAPLE will parse only, and can be used without starting up MapleV first."
  101.          say ""
  102.          say "     ASYNC will  allow  the  parse  to  continue  asynchronously  with  MapleV's"
  103.          say "     execution.  Otherwise,  the  parse will wait for MapleV to stop calculating"
  104.          say "     before sending it any input string that requires computation."
  105.          say ""
  106.          say "IMPLEMENTATION"
  107.          say "     ReadWorkSheet.rexx uses recursive  descent  parsing  to  parse  the  MapleV"
  108.          say "     worksheet.  The  syntax  of  a  MapleV Worksheet is described in psuedo-BNF"
  109.          say "     format in comments within  the  program.  There  are  also  several  useful"
  110.          say "     subroutines   for   parsing   (GetChar,  UnGetChar,  GetToken,  UnGetToken,"
  111.          say "     ParseTrace, ParseTraceEntry, ParseTraceExit, and TokenTrace."
  112.          say ""
  113.          say "     Unfortunately, ReadWorkSheet.rexx can run very slowly, as it must skip over"
  114.          say "     all  of  the  worksheet  text  that  represents graphics data, typeset math"
  115.          say "     expressions, or MapleV output."
  116.          say ""
  117.          say "     The syntax of MapleV worksheets  was  derived  by  careful  examination  of"
  118.          say "     numerous MapleV worksheets, many of which were obtained from the Net."
  119.          say ""
  120.          say "     This program was motivated by the fact that Amiga MapleV on my machine,  in"
  121.          say "     my environment, gurus when fed a non-Amiga MapleV worksheet."
  122.          say ""
  123.          say "     If you encounter a valid MapleV worksheet that causes ReadWorkSheet.rexx to"
  124.          say "     report  a  syntax error, please lha it, uuencode that, and email the result"
  125.          say "     to me at: tboeckel@uni-paderborn.de"
  126.          say ""
  127.          say "     I also welcome any other comments, bug reports, or suggestions. I  am  also"
  128.          say "     interested   in  any  deeper  secrets  about  Maple  worksheet  structures,"
  129.          say "     especially the DAG, DIB, and AGR regions, and the meanings of  the  various"
  130.          say "     flags and numeric values found in a Maple worksheet."
  131.          say ""
  132.          say "AUTHOR"
  133.          say "     Joe Veazey: 73227.2656@compuserve.com (first version)"
  134.          say "     Thore Boeckelmann: tboeckel@uni-paderborn.de"
  135.          say ""
  136.          exit 5
  137.        end
  138.  
  139. WsIn = 'WsIn'
  140. if ~open(WsIn, FileName, 'R') ,
  141.   then do
  142.          Say "Can't open file" FileName
  143.          return 20
  144.        end
  145.  
  146. PortName = "MAPLE1"
  147. address value PortName
  148.  
  149. call GetToken()                         /* Prime the Pump */
  150.  
  151. myRC = 0
  152. if WorkSheet() ,                        /* Parse the entire worksheet */
  153.   then say "WorkSheet successful"
  154.   else do
  155.          say "WorkSheet failed"
  156.          myRC = 10
  157.        end
  158.  
  159. call close(WsIn)
  160. exit myRC
  161.  
  162. /* Panic if a syntax error occurs */
  163. syntax: say "*** Syntax Error ***"
  164.   say LexState.CurrentLine
  165.   say    right("",LexState.CurrentCol-1,"-") ,
  166.       || "|<--- Column("LexState.CurrentCol") Line" LexState.LineNumber
  167.   say ""
  168.   say "Token <"ParseState.CurrentToken"> Type <"ParseState.TokenType"> Failed to match"
  169.   say "SIGL="sigl"; SourceLine=<"sourceline(sigl)">"
  170. exit 10
  171.  
  172.  
  173. /*
  174.  * WorkSheet    :=      "{" VersionSpec "}"
  175.  *                      ( "{" GlobalSpec "}"
  176.  *                        "{" ScpRegion | FontRegion | "END" "}" ... ) |
  177.  *                      ( "{" UStyleTabRegion "}"
  178.  *                        "{" SectionRegion "}" ...
  179.  *                        "{" MarkSection "}"
  180.  *                        "{" ViewOptsSection "}" )
  181.  *                      /*EOF*/ ;
  182.  */
  183. WorkSheet: procedure expose WsIn LexState. ParseState. ExecuteState.
  184.  
  185.   if ~MatchOperator("{")        then return 0
  186.                 call ParseTraceEntry("WorkSheet")
  187.   if ~VersionSpec()             then signal syntax      /* FALSE means not matched */
  188.   if ~MatchOperator("}")        then signal syntax
  189.  
  190.   if ~MatchOperator("{")        then signal syntax
  191.        if GlobalSpec() then mapleVer=3
  192.   else if UStyleTabRegion() then mapleVer=4
  193.   else signal syntax      /* 10 means error */
  194.   if ~MatchOperator("}")        then signal syntax
  195.  
  196.   if mapleVer=3 then do /* MapleV R3 Worksheet */
  197.     say "This is an MapleV R3 Worksheet"
  198.     do forever
  199.       if ~MatchOperator("{")      then signal syntax
  200.  
  201.            if ~ScpRegion() ,
  202.       then if ~FontRegion() ,
  203.       then if ~MatchKeyWord("END")then signal syntax
  204.       else leave
  205.  
  206.       if ~MatchOperator("}")      then signal syntax
  207.     end
  208.  
  209.     if ~MatchOperator("}")        then signal syntax      /* Catch "}" from END */
  210.     if ~MatchEOF()                then signal syntax
  211.   end
  212.   else if mapleVer=4 then do /* MapleV R4+ Worksheet */
  213.     say "This is an MapleV R4 Worksheet"
  214.     do forever
  215.       if MatchEOF()               then leave
  216.       if ~MatchOperator("{")      then signal syntax
  217.  
  218.            if ~SectionRegion() ,
  219.       then if ~MarkSection() ,
  220.       then if ~ViewOptsSection()  then signal syntax
  221.       else leave
  222.  
  223.       if ~MatchOperator("}")      then signal syntax
  224.     end
  225.  end
  226.  
  227.                 call ParseTraceExit("WorkSheet")
  228. return 1                                                /* TRUE (1) means parsed OK */
  229.  
  230.  
  231. /*
  232.  * VersionSpec  := "VERSION" VersionNumA VersionNumB
  233.  *                           SystemString VersionString ;
  234.  */
  235. VersionSpec: procedure expose WsIn LexState. ParseState. ExecuteState.
  236.  
  237.   if ~MatchKeyWord("VERSION")   then return 0
  238.                 call ParseTraceEntry("VersionSpec")
  239.   if ~MatchNumber()             then signal syntax      /* VersionNumA */
  240.         /* VersionNumA = ParseState.TokenValue */
  241.   if ~MatchNumber()             then signal syntax      /* VersionNumB */
  242.         /* VersionNumB = ParseState.TokenValue */
  243.   if ~MatchStringQQ()           then signal syntax      /* SystemString */
  244.         SystemString = ParseState.TokenValue
  245.   if ~MatchStringQQ()           then signal syntax      /* VersionString */
  246.         /* VersionString = ParseState.TokenValue */
  247.                 call ParseTrace("SystemString =" SystemString)
  248.                 call ParseTraceExit("VersionSpec")
  249. return 1                                                /* TRUE (1) means parsed OK */
  250.  
  251.  
  252. /*
  253.  * GlobalSpec   := "GLOBALS" GlobalNumA GlobalNumB ;
  254.  */
  255. GlobalSpec: procedure expose WsIn LexState. ParseState. ExecuteState.
  256.  
  257.   if ~MatchKeyWord("GLOBALS")   then return 0
  258.                 call ParseTraceEntry("GlobalSpec")
  259.   if ~MatchNumber()             then signal syntax;     /* GlobalNumA */
  260.   if ~MatchNumber()             then signal syntax;     /* GlobalNumB */
  261.                 call ParseTraceExit("GlobalSpec")
  262. return 1
  263.  
  264.  
  265. /*
  266.  * UStyleTabRegion := "USTYLETAB" "{" CStyleSpec | PStyleRegion "}";
  267.  */
  268. UStyleTabRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  269.  
  270.   if ~MatchKeyWord("USTYLETAB")   then return 0
  271.                 call ParseTraceEntry("UStyleTabRegion")
  272.   do forever
  273.     if ~MatchOperator("{")         then leave /* signal syntax */
  274.          if ~CStyleSpec() ,
  275.     then if ~PStyleRegion()        then signal syntax
  276.     if ~MatchOperator("}")         then signal syntax
  277.   end
  278.                 call ParseTraceExit("UStyleTabRegion")
  279. return 1                                                /* TRUE (1) means parsed OK */
  280.  
  281.  
  282. /* CStyleSpec := "CSTYLE" StyleName Num1 Num2 FontName
  283.  *                        NumF1 NumF2 NumF3 NumF4 NumF5 NumF6 NumF7
  284.  *                        NumF8 NumF9 NumF10 NumF11 NumF12 NumF13 NumF14 NumF15;
  285.  */
  286. CStyleSpec: procedure expose WsIn LexState. ParseState. ExecuteState.
  287.  
  288.   if ~MatchKeyWord("CSTYLE")    then return 0
  289.                 call ParseTraceEntry("CStyleSpec")
  290.   if ~MatchStringQQ()           then signal syntax;     /* StyleName */
  291.         StyleName = ParseState.TokenValue
  292.   if ~MatchNumber()             then signal syntax;
  293.   if ~MatchNumber()             then signal syntax;
  294.   if ~MatchStringQQ()           then signal syntax;     /* FontName */
  295.         FontName = ParseState.TokenValue
  296.   if ~MatchNumber()             then signal syntax;
  297.   if ~MatchNumber()             then signal syntax;
  298.   if ~MatchNumber()             then signal syntax;
  299.   if ~MatchNumber()             then signal syntax;
  300.   if ~MatchNumber()             then signal syntax;
  301.   if ~MatchNumber()             then signal syntax;
  302.   if ~MatchNumber()             then signal syntax;
  303.   if ~MatchNumber()             then signal syntax;
  304.   if ~MatchNumber()             then signal syntax;
  305.   if ~MatchNumber()             then signal syntax;
  306.   if ~MatchNumber()             then signal syntax;
  307.   if ~MatchNumber()             then signal syntax;
  308.   if ~MatchNumber()             then signal syntax;
  309.   if ~MatchNumber()             then signal syntax;
  310.   if ~MatchNumber()             then signal syntax;
  311.                 call ParseTrace("StyleName '"StyleName"' specifies font '"FontName"'")
  312.                 call ParseTraceExit("CStyleSpec")
  313. return 1
  314.  
  315.  
  316. /* PStyleRegion := "PSTYLE" StyleName Num1 Num2 Num3 "{" CSTYLE "}";
  317.  */
  318. PStyleRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  319.  
  320.   if ~MatchKeyWord("PSTYLE")    then return 0
  321.                 call ParseTraceEntry("PStyleRegion")
  322.   if ~MatchStringQQ()           then signal syntax;     /* StyleName */
  323.         StyleName = ParseState.TokenValue
  324.   if ~MatchNumber()             then signal syntax;
  325.   if ~MatchNumber()             then signal syntax;
  326.   if ~MatchNumber()             then signal syntax;
  327.                 call ParseTrace("StyleName '"StyleName"'")
  328.   if ~MatchOperator("{")        then signal syntax
  329.   if ~CStyleSpec()              then signal syntax
  330.   if ~MatchOperator("}")        then signal syntax
  331.   if ~MatchNumber()             then signal syntax;
  332.   if ~MatchNumber()             then signal syntax;
  333.   if ~MatchNumber()             then signal syntax;
  334.   if ~MatchNumber()             then signal syntax;
  335.   if ~MatchNumber()             then signal syntax;
  336.   if ~MatchNumber()             then signal syntax;
  337.   if ~MatchNumber()             then signal syntax;
  338.   if ~MatchNumber()             then signal syntax;
  339.   if ~MatchNumber()             then signal syntax;
  340.   if ~MatchNumber()             then signal syntax;
  341.   if ~MatchNumber()             then signal syntax;
  342.   if ~MatchNumber()             then signal syntax;
  343.   if ~MatchNumber()             then signal syntax;
  344.   if ~MatchNumber()             then signal syntax;
  345.                 call ParseTraceExit("PStyleRegion")
  346. return 1
  347.  
  348.  
  349. /* SectionRegion   := "SECT" SectNumber
  350.  *                           "{" ExchgSection | SectionRegion | ParaSection "}";
  351.  */
  352. SectionRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  353.  
  354.   if ~MatchKeyWord("SECT")      then return 0
  355.                 call ParseTraceEntry("SectionRegion")
  356.   if ~MatchNumber()             then signal syntax;     /* SectNumber */
  357.         SectNumber = ParseState.TokenValue
  358.                 call ParseTrace("SectionNumber" SectNumber)
  359.   do forever
  360.     if ~MatchOperator("{")      then leave
  361.          if ~ExchgSection() ,
  362.     then if ~SectionRegion() ,
  363.     then if ~ParaSection()      then signal syntax
  364.     if ~MatchOperator("}")      then signal syntax
  365.   end
  366.                 call ParseTraceExit("SectionRegion: " || SectNumber)
  367. return 1
  368.  
  369.  
  370. /*
  371.  * ExchgSection := "EXCHG" "{" ParaSection ... "}";
  372.  */
  373. ExchgSection: procedure expose WsIn LexState. ParseState. ExecuteState.
  374.  
  375.   if ~MatchKeyWord("EXCHG")     then return 0
  376.                 call ParseTraceEntry("ExchgSection")
  377.   do forever
  378.     if ~MatchOperator("{")      then leave
  379.     if ~ParaSection()           then signal syntax
  380.     if ~MatchOperator("}")      then signal syntax
  381.   end
  382.                 call ParseTraceExit("ExchgSection")
  383. return 1
  384.  
  385.  
  386. /*
  387.  * ParaSection := "PARA" ParaNumber BegString Num1 SecString
  388.  *                       "{" TextRegion | MapleTextRegion | XPPMathRegion | XPPEditRegion |
  389.  *                           HyperLinkRegion | InlinePlotRegion "}";
  390.  */
  391. ParaSection: procedure expose WsIn LexState. ParseState. ExecuteState.
  392.  
  393.   if ~MatchKeyWord("PARA")      then return 0
  394.                 call ParseTraceEntry("ParagraphSection")
  395.   if ~MatchNumber()             then signal syntax      /* ParaNumber */
  396.         ParaNumber = ParseState.TokenValue
  397.   if ~MatchStringQQ()           then signal syntax      /* BegString */
  398.         BegString = ParseState.TokenValue
  399.   if ~MatchNumber()             then signal syntax      /* Num1 */
  400.   if ~MatchStringQQ()           then signal syntax      /* SecString */
  401.                 call ParseTrace("ParagraphSection" ParaNumber "starts with '"BegString"'")
  402.  
  403.   oldtextType=-1
  404.   do forever
  405.     if ~MatchOperator("{")        then leave
  406.          if TextRegion() then textType=0
  407.     else if MapleTextRegion() then textType=1
  408.     else if XPPMathRegion() then textType=2
  409.     else if XPPEditRegion() then textType=0
  410.     else if HyperLinkRegion() then textType=0
  411.     else if InlinePlotRegion() then textType=2
  412.     else signal syntax
  413.     if ~MatchOperator("}")        then signal syntax
  414.  
  415.     select
  416.       when textType=0 then do /* Kommentar */
  417.         if ExecuteState.CallMaple ,
  418.           then do
  419.                       call ParseTrace("Inserting Comment Region")
  420.                  if textType ~= oldtextType then do
  421.                    "EndOfRegion"
  422.                    "NewText"
  423.                  end
  424.                  "Insert" ParseState.SemanticText
  425.                  call SendReturn()
  426.                end
  427.           else say "Comment Region contained text: <" ParseState.SemanticText ">"
  428.       end
  429.       when textType=1 then do
  430.         if ExecuteState.CallMaple ,
  431.           then do
  432.                       call ParseTrace("Inserting Input Region")
  433.                  if textType ~= oldtextType then do
  434.                    "EndOfRegion"
  435.                    "NewInput"
  436.                  end
  437.                  "Insert" ParseState.SemanticText
  438.                  call SendReturn()
  439.                end
  440.           else say "Input Region contained text: <" ParseState.SemanticText ">"
  441.       end
  442.       when textType=2 then do
  443.         nop
  444.       end
  445.     end
  446.     oldtextType=textType
  447.   end
  448.                   call ParseTraceExit("ParagraphSection")
  449. return 1
  450.  
  451.  
  452. /*
  453.  *  MarkSection := "MARK" MarkText Number ;
  454.  */
  455. MarkSection: procedure expose WsIn LexState. ParseState. ExecuteState.
  456.  
  457.   if ~MatchKeyWord("MARK")      then return 0
  458.                 call ParseTraceEntry("MarkSection")
  459.   if ~MatchStringQQ()           then signal syntax;     /* MarkText */
  460.   if ~MatchNumber()             then signal syntax;     /* Number */
  461.                 call ParseTraceExit("MarkSection")
  462. return 1
  463.  
  464.  
  465. /*
  466.  *  ViewOptsSection := "VIEWOPTS" Opt1 Opt2 Opt3 Opt4 Opt5 Opt6
  467.  */
  468. ViewOptsSection: procedure expose WsIn LexState. ParseState. ExecuteState.
  469.  
  470.   if ~MatchKeyWord("VIEWOPTS")  then return 0
  471.                 call ParseTraceEntry("ViewOptsSection")
  472.   if ~MatchNumber()             then signal syntax;     /* Opt1 */
  473.   if ~MatchNumber()             then signal syntax;     /* Opt2 */
  474.   if ~MatchNumber()             then signal syntax;     /* Opt3 */
  475.   if ~MatchNumber()             then signal syntax;     /* Opt4 */
  476.   if ~MatchNumber()             then signal syntax;     /* Opt5 */
  477.   if ~MatchNumber()             then signal syntax;     /* Opt6 */
  478.                 call ParseTraceExit("ViewOptsSection")
  479. return 1
  480.  
  481.  
  482. /* FontRegion   := "FONT" FontNumber FontString1 FontString2 FontString3
  483.  *                        FontNumA FontSize1 FontFlags FontString4 FontSize4
  484.  *                         "{" ColorSpec "}";
  485.  */
  486. FontRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  487.  
  488.   if ~MatchKeyWord("FONT")      then return 0
  489.                 call ParseTraceEntry("FontRegion")
  490.   if ~MatchNumber()             then signal syntax;     /* FontNumber */
  491.         FontNumber = ParseState.TokenValue
  492.   if ~MatchStringQQ()           then signal syntax      /* FontString1 */
  493.         FontString1 = ParseState.TokenValue
  494.   if ~MatchStringQQ()           then signal syntax      /* FontString2 */
  495.         FontString2 = ParseState.TokenValue
  496.   if ~MatchStringQQ()           then signal syntax      /* FontString3 */
  497.         FontString3 = ParseState.TokenValue
  498.   if ~MatchNumber()             then signal syntax;     /* FontNumA */
  499.   if ~MatchNumber()             then signal syntax;     /* FontSize1 */
  500.         FontSize1 = ParseState.TokenValue
  501.   if ~MatchNumber()             then signal syntax;     /* FontFlags */
  502.  
  503.   if ~MatchStringQQ()           then signal syntax      /* FontString4 */
  504.         FontString4 = ParseState.TokenValue
  505.   if ~MatchNumber()             then signal syntax;     /* FontSize4 */
  506.                 call ParseTrace("FontNumber" FontNumber "specifies fonts" FontString1 FontString2 FontString3 FontString4 "at size" FontSize1)
  507.   if ~MatchOperator("{")        then signal syntax
  508.   if ~ColorSpec()               then signal syntax
  509.   if ~MatchOperator("}")        then signal syntax
  510.                 call ParseTraceExit("FontRegion: " || FontNumber)
  511. return 1
  512.  
  513.  
  514. /* ColorSpec    := "COLOR" ColorFlagsString ;
  515.  */
  516. ColorSpec: procedure expose WsIn LexState. ParseState. ExecuteState.
  517.  
  518.   if ~MatchKeyWord("COLOR")     then return 0
  519.                 call ParseTraceEntry("ColorSpec")
  520.   if ~MatchStringQQ()           then signal syntax;     /* ColorFlagsString */
  521.                 call ParseTraceExit("ColorSpec")
  522. return 1
  523.  
  524.  
  525. /*
  526.  * RegionObject := "{"  ScpRegion
  527.  *                    | ComRegion
  528.  *                    | InpRegion
  529.  *                    | OutRegion
  530.  *                    | AgrRegion
  531.  *                    | CgrRegion
  532.  *                 "}";
  533.  */
  534. RegionObject: procedure expose WsIn LexState. ParseState. ExecuteState.
  535.  
  536.   if ~MatchOperator("{")        then return 0;
  537.                 call ParseTraceEntry("RegionObject")
  538.  
  539.        if ~ScpRegion() ,
  540.   then if ~ComRegion() ,
  541.   then if ~InpRegion() ,
  542.   then if ~OutRegion() ,
  543.   then if ~AgrRegion() ,
  544.   then if ~CgrRegion()          then signal syntax
  545.  
  546.   if ~MatchOperator("}")        then signal syntax;
  547.                 call ParseTraceExit("RegionObject")
  548. return 1
  549.  
  550.  
  551. /*
  552.  * ScpRegion    :=  "SCP_R" RegionNumber RegionNumB RegionCount
  553.  *                          RegionObject(s)... ;
  554.  */
  555. ScpRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  556.  
  557.   if ~MatchKeyWord("SCP_R")     then return 0
  558.                 call ParseTraceEntry("ScpRegion")
  559.   if ~RegionNumber()            then signal syntax;     /* RegionNumber */
  560.         ThisRegionNumber = ParseState.TokenValue
  561.  
  562.   if ~MatchNumber()             then signal syntax;     /* RegionNumB */
  563.  
  564.   if ~MatchNumber()             then signal syntax;     /* RegionCount */
  565.   RegionCount = ParseState.TokenValue
  566.                 call ParseTrace("ScpRegion" ThisRegionNumber "has" RegionCount "subregions")
  567.   do ii=0 by 1 for RegionCount
  568.                 call ParseTrace("Processing ScpRegion."ThisRegionNumber"."ii)
  569.     if ~RegionObject()          then signal syntax;
  570.   end
  571.                 call ParseTraceExit("ScpRegion: "|| ThisRegionNumber)
  572. return 1
  573.  
  574.  
  575. /*
  576.  * ComRegion    := "COM_R" RegionNumber RegionNumB "{" TextRegion "}" ;
  577.  */
  578. ComRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  579.  
  580.   if ~MatchKeyWord("COM_R")     then return 0
  581.                 call ParseTraceEntry("ComRegion")
  582.   if ~RegionNumber()            then signal syntax;     /* RegionNumber */
  583.         ThisRegionNumber = ParseState.TokenValue
  584.  
  585.   if ~MatchNumber()             then signal syntax;     /* RegionNumB */
  586.   if ~MatchOperator("{")        then signal syntax;
  587.   if ~TextRegion()              then signal syntax;
  588.  
  589.   if ExecuteState.CallMaple ,
  590.     then do
  591.                 call ParseTrace("Inserting Comment Region" ThisRegionNumber '0A'x"<" ParseState.SemanticText ">")
  592.            "EndOfRegion"
  593.            "NewText"
  594.            "Insert" ParseState.SemanticText
  595.          end
  596.     else say "Comment Region" ThisRegionNumber "contained text:" '0A'x"<" ParseState.SemanticText ">"
  597.  
  598.   if ~MatchOperator("}")        then signal syntax;
  599.                 call ParseTraceExit("ComRegion: "|| ThisRegionNumber)
  600. return 1
  601.  
  602.  
  603. /*
  604.  * InpRegion    := "INP_R" RegionNumber RegionNumB [ PromptString ]
  605.  *                              "{" TextRegion "}" ;
  606.  */
  607. InpRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  608.  
  609.   if ~MatchKeyWord("INP_R")     then return 0
  610.                 call ParseTraceEntry("InpRegion")
  611.   if ~RegionNumber()            then signal syntax;     /* RegionNumber */
  612.         ThisRegionNumber = ParseState.TokenValue
  613.  
  614.   if ~MatchNumber()             then signal syntax;     /* RegionNumB */
  615.   if  MatchStringQQ()           then nop                /* PromptString  (optional) */
  616.   if ~MatchOperator("{")        then signal syntax;
  617.   if ~TextRegion()              then signal syntax;
  618.   if ~MatchOperator("}")        then signal syntax;
  619.  
  620.  
  621.   if ExecuteState.CallMaple ,
  622.     then do
  623.                 call ParseTrace("Inserting Input Region" ThisRegionNumber '0A'x"<" ParseState.SemanticText ">")
  624.            "EndOfRegion"
  625.            "NewInput"
  626.            "Insert" ParseState.SemanticText
  627.            call SendReturn()
  628.          end
  629.     else say "Input Region" ThisRegionNumber "contained text:" '0A'x"<" ParseState.SemanticText ">"
  630.                 call ParseTraceExit("InpRegion: "|| ThisRegionNumber)
  631. return 1
  632.  
  633.  
  634. /* OutRegion    := "OUT_R" RegionNumber RegionNumB DagSize
  635.  *                         "{" [ DagRegion | TextRegion ]"}";
  636.  */
  637. OutRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  638.  
  639.   if ~MatchKeyWord("OUT_R")     then return 0
  640.                 call ParseTraceEntry("OutRegion")
  641.   if ~RegionNumber()            then signal syntax;     /* RegionNumber */
  642.         ThisRegionNumber = ParseState.TokenValue
  643.   if ~MatchNumber()             then signal syntax;     /* RegionNumB */
  644.   if ~MatchNumber()             then signal syntax;     /* DagSize */
  645.  
  646.   if ~MatchOperator("{")        then signal syntax;
  647.        if ~DagRegion()
  648.   then if ~TextRegion()         then signal syntax;
  649.   if ~MatchOperator("}")        then signal syntax;
  650.                 call ParseTraceExit("OutRegion: " || ThisRegionNumber)
  651. return 1
  652.  
  653.  
  654. /* DagRegion    := "DAG" <anything but "}" or EOF> ;
  655.  */
  656. DagRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  657.  
  658.   if ~MatchKeyWord("DAG")       then return 0
  659.                 call ParseTraceEntry("DagRegion")
  660.                 call ParseTrace("Skipping Dag data")
  661.   do until MatchOperator("}") | MatchEOF()
  662.     call GetToken()
  663.   end
  664.   call UnGetToken()
  665.                 call ParseTrace("Dag data skipped")
  666.                 call ParseTraceExit("DagRegion")
  667. return 1
  668.  
  669.  
  670. /* CgrRegion    := "CGR_R" RegionNumber  DibSize
  671.  *                         "{" DibRegion "}";
  672.  */
  673. CgrRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  674.  
  675.   if ~MatchKeyWord("CGR_R")     then return 0
  676.                 call ParseTraceEntry("CgrRegion")
  677.   if ~RegionNumber()            then signal syntax;     /* RegionNumber */
  678.         ThisRegionNumber = ParseState.TokenValue
  679.  
  680.   if ~MatchNumber()             then signal syntax;     /* DibSize */
  681.  
  682.   if ~MatchOperator("{")        then signal syntax;
  683.   if ~DibRegion()               then signal syntax;
  684.   if ~MatchOperator("}")        then signal syntax;
  685.                 call ParseTraceExit("CgrRegion: " || ThisRegionNumber)
  686. return 1
  687.  
  688.  
  689. /* DibRegion    := "DIB" DibNumA DibSize DigData> ;
  690.  */
  691. DibRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  692.  
  693.   if ~MatchKeyWord("DIB")       then return 0
  694.                 call ParseTraceEntry("DibRegion")
  695.   if ~MatchNumber()             then signal syntax      /* DibNumA */
  696.   if ~MatchNumber()             then signal syntax      /* DibSize */
  697.   if ~DibData()                 then signal syntax      /* DibData */
  698.                 call ParseTraceExit("DibRegion")
  699. return 1
  700.  
  701.  
  702. /* DibData := <anything but "}" or EOF>;
  703.  */
  704. DibData: procedure expose WsIn LexState. ParseState. ExecuteState.
  705.                 call ParseTraceEntry("DibData")
  706.         call ParseTrace("Skipping Dib data")
  707.   do until ( (CurrentChar == "}") | (CurrentChar == '04'x) )
  708.     CurrentChar = GetChar()
  709.   end
  710.   call UnGetChar()
  711.   call GetToken()                                       /* Sync GetToken & GetChar */
  712.   call UnGetToken()                                     /* Put the "}" back */
  713.                 call ParseTrace("Dib data skipped")
  714.                 call ParseTraceExit("DibData")
  715. return 1
  716.  
  717.  
  718. /* AgrRegion    := "AGR_R" RegionNumber RegionNumB
  719.  *                     StringList ;
  720.  */
  721. AgrRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  722.  
  723.   if ~MatchKeyWord("AGR_R")     then return 0
  724.                 call ParseTraceEntry("AgrRegion")
  725.   if ~RegionNumber()            then signal syntax;     /* RegionNumber */
  726.         ThisRegionNumber = ParseState.TokenValue
  727.   if ~MatchNumber()             then signal syntax;     /* RegionNumB */
  728.   if ~StringList()              then signal syntax;
  729.                 call ParseTraceExit("AgrRegion: " || ThisRegionNumber)
  730. return 1
  731.  
  732.  
  733. /*
  734.  *  TextRegion   := "TEXT" FontNumber TextSize TextString ;
  735.  */
  736. TextRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  737.  
  738.   if ~MatchKeyWord("TEXT")      then return 0
  739.                 call ParseTraceEntry("TextRegion")
  740.   if ~MatchNumber()             then signal syntax;     /* FontNumber */
  741.   if ~MatchNumber()             then signal syntax;     /* TextSize */
  742.   if ~MatchStringQQ()           then signal syntax;     /* Quoted Text */
  743.         ParseState.SemanticText = ParseState.TokenValue
  744.                 call ParseTraceExit("TextRegion")
  745. return 1
  746.  
  747.  
  748. /*
  749.  *  MapleTextRegion   := "MPLTEXT" FontNumber ParaNumber TextSize TextString ;
  750.  */
  751. MapleTextRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  752.  
  753.   if ~MatchKeyWord("MPLTEXT")   then return 0
  754.                 call ParseTraceEntry("MapleTextRegion")
  755.   if ~MatchNumber()             then signal syntax;     /* FontNumber */
  756.   if ~MatchNumber()             then signal syntax;     /* ParaNumber */
  757.   if ~MatchNumber()             then signal syntax;     /* TextSize */
  758.   if ~MatchStringQQ()           then signal syntax;     /* Quoted Text */
  759.         ParseState.SemanticText = ParseState.TokenValue
  760.                 call ParseTraceExit("MapleTextRegion")
  761. return 1
  762.  
  763.  
  764. /*
  765.  *  XPPMathRegion   := "XPPMATH" TextSize TextString ;
  766.  */
  767. XPPMathRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  768.  
  769.   if ~MatchKeyWord("XPPMATH")   then return 0
  770.                 call ParseTraceEntry("XPPMathRegion")
  771.   if ~MatchNumber()             then signal syntax;     /* TextSize */
  772.   if ~MatchStringQQ()           then signal syntax;     /* Quoted Text */
  773.         ParseState.SemanticText = ParseState.TokenValue
  774.                 call ParseTraceExit("XPPMathRegion")
  775. return 1
  776.  
  777.  
  778. /*
  779.  *  XPPEditRegion   := "XPPEDIT" Num1 Num2 Text MathStuff;
  780.  */
  781. XPPEditRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  782.  
  783.   if ~MatchKeyWord("XPPEDIT")   then return 0
  784.                 call ParseTraceEntry("XPPEditRegion")
  785.   if ~MatchNumber()             then signal syntax;     /* Num1 */
  786.   if ~MatchNumber()             then signal syntax;     /* Num2 */
  787.   if ~MatchStringQQ()           then signal syntax;     /* Quoted Text */
  788.         ParseState.SemanticText = ParseState.TokenValue
  789.   if ~MatchStringQQ()           then signal syntax;     /* MathStuff */
  790.                 call ParseTraceExit("XPPEditRegion")
  791. return 1
  792.  
  793.  
  794. /*
  795.  *  HyperLinkRegion   := "HYPERLNK" LinkNum1 LinkText LinkNum2 LinkFile Text;
  796.  */
  797. HyperLinkRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  798.  
  799.   if ~MatchKeyWord("HYPERLNK")  then return 0
  800.                 call ParseTraceEntry("HyperLinkRegion")
  801.   if ~MatchNumber()             then signal syntax;     /* LinkNum1 */
  802.   if ~MatchStringQQ()           then signal syntax;     /* LinkText */
  803.         ParseState.SemanticText = " _" || ParseState.TokenValue || "_ "
  804.   if ~MatchNumber()             then signal syntax;     /* LinkNum2 */
  805.   if ~MatchStringQQ()           then signal syntax;     /* LinkFile */
  806.   if ~MatchStringQQ()           then signal syntax;     /* Text */
  807.                 call ParseTraceExit("HyperLinkRegion")
  808. return 1
  809.  
  810.  
  811. /*
  812.  *  InlinePlotRegion   := "INLPLOT" PlotText Num1 .. Num44;
  813.  */
  814. InlinePlotRegion: procedure expose WsIn LexState. ParseState. ExecuteState.
  815.  
  816.   if ~MatchKeyWord("INLPLOT")   then return 0
  817.                 call ParseTraceEntry("InlinePlotRegion")
  818.   if ~MatchStringQQ()           then signal syntax;     /* PlotText */
  819.   do ii=1 by 1 for 13
  820.     if ~MatchNumber()           then signal syntax;     /* LinkNumX */
  821.   end
  822.   do ii=14 by 1 for 3
  823.     if ~MatchReal()             then signal syntax;     /* LinkNumX */
  824.   end
  825.   do ii=17 by 1 for 29
  826.     if ~MatchNumber()           then signal syntax;     /* LinkNumX */
  827.   end
  828.                 call ParseTraceExit("InlinePlotRegion")
  829. return 1
  830.  
  831.  
  832. /* RegionNumber := Number ;
  833.  */
  834. RegionNumber: procedure expose WsIn LexState. ParseState. ExecuteState.
  835.  
  836.   if ~MatchNumber() then return 0
  837.                 call ParseTrace("Processing RegionNumber =" ParseState.TokenValue)
  838. return 1
  839.  
  840.  
  841. /* StringList := String
  842.  *             | String StringList;
  843.  */
  844. StringList: procedure expose WsIn LexState. ParseState. ExecuteState.
  845.  
  846.   if ~MatchStringQQ() then return 0;
  847.                 call ParseTraceEntry("StringList")
  848.   do while MatchStringQQ();
  849.   end
  850.                 call ParseTraceExit("StringList")
  851. return 1
  852.  
  853.  
  854. /* Match a specified operator
  855.  * If not matched: Return FALSE (0)
  856.  * Else GetToken, and Return TRUE (1)
  857.  */
  858. MatchOperator: procedure expose WsIn LexState. ParseState. ExecuteState.
  859.  
  860. TargetOp = arg(1)
  861.   if ParseState.TokenType    ~== "/*OP*/" then return 0
  862.   if ParseState.CurrentToken ~== TargetOp then return 0
  863.   call GetToken()
  864.  
  865. return 1                                /* TRUE (1) means matched */
  866.  
  867.  
  868. /* Match a specified keyword
  869.  * If not matched: Return FALSE (0)
  870.  * Else GetToken, and Return TRUE (1)
  871.  */
  872. MatchKeyWord: procedure expose WsIn LexState. ParseState. ExecuteState.
  873.  
  874. TargetKeyWord = arg(1)
  875.   if ParseState.TokenType    ~== "/*KEY*/"      then return 0
  876.   if ParseState.CurrentToken ~== TargetKeyWord  then return 0
  877.   call GetToken()
  878.  
  879. return 1                                /* TRUE (1) means matched */
  880.  
  881.  
  882. /* Match an identifier
  883.  * If not matched: Return FALSE (0)
  884.  * Else GetToken, and Return TRUE (1)
  885.  */
  886. MatchIdentifier: procedure expose WsIn LexState. ParseState. ExecuteState.
  887.  
  888.   if ParseState.TokenType ~== "/*KEY*/" then return 0
  889.   ParseState.TokenValue = ParseState.CurrentToken
  890.   call GetToken()
  891.  
  892. return 1                                /* TRUE (1) means matched */
  893.  
  894.  
  895. /* Match a number
  896.  * If not matched: Return FALSE (0)
  897.  * Else GetToken, and Return TRUE (1)
  898.  * Value of number returned in ParseState.TokenValue
  899.  */
  900. MatchNumber: procedure expose WsIn LexState. ParseState. ExecuteState.
  901.  
  902.   if ParseState.TokenType ~== "/*NUM*/" then return 0
  903.   ParseState.TokenValue = 0 + ParseState.CurrentToken
  904.   call GetToken()
  905.  
  906. return 1                                /* TRUE (1) means matched */
  907.  
  908.  
  909. /* Match a real number
  910.  * If not matched: Return FALSE (0)
  911.  * Else GetToken, and Return TRUE (1)
  912.  * Value of number returned in ParseState.TokenValue
  913.  */
  914. MatchReal: procedure expose WsIn LexState. ParseState. ExecuteState.
  915.  
  916.   if ~MatchNumber()             then signal syntax;
  917.   value = ParseState.TokenValue;
  918.   if ~MatchOperator(".")        then signal syntax;
  919.   if ~MatchNumber()             then signal syntax;
  920.   fraction = ParseState.TokenValue;
  921.   ParseState.TokenValue = value + fraction/1000000
  922.  
  923. return 1                                /* TRUE (1) means matched */
  924.  
  925.  
  926. /* Match a "string"
  927.  * If not matched: Return FALSE (0)
  928.  * Else GetToken, and Return TRUE (1)
  929.  * Contents of string returned in ParseState.TokenValue
  930.  */
  931. MatchStringQQ: procedure expose WsIn LexState. ParseState. ExecuteState.
  932.  
  933.   if ParseState.TokenType ~== "/*STRQQ*/" then return 0
  934.   ParseState.TokenValue = ParseState.CurrentToken
  935.   call GetToken()
  936.  
  937. return 1                                /* TRUE (1) means matched */
  938.  
  939.  
  940. /* Match a 'string'
  941.  * If not matched: Return FALSE (0)
  942.  * Else GetToken, and Return TRUE (1)
  943.  * Contents of string returned in ParseState.TokenValue
  944.  */
  945. MatchStringQ: procedure expose WsIn LexState. ParseState. ExecuteState.
  946.  
  947.   if ParseState.TokenType ~== "/*STRQ*/" then return 0
  948.   ParseState.TokenValue = ParseState.CurrentToken
  949.   call GetToken()
  950.  
  951. return 1                                /* TRUE (1) means matched */
  952.  
  953.  
  954. /* Match a `string`
  955.  * If not matched: Return FALSE (0)
  956.  * Else GetToken, and Return TRUE (1)
  957.  * Contents of string returned in ParseState.TokenValue
  958.  */
  959. MatchStringT: procedure expose WsIn LexState. ParseState. ExecuteState.
  960.  
  961.   if ParseState.TokenType ~== "/*STRTIC*/" then return 0
  962.   ParseState.TokenValue = ParseState.CurrentToken
  963.   call GetToken()
  964.  
  965. return 1                                /* TRUE (1) means matched */
  966.  
  967.  
  968. /* Match EOF
  969.  * If not matched: Return FALSE.
  970.  * Else Return TRUE (1)
  971.  */
  972. MatchEOF: procedure expose WsIn LexState. ParseState. ExecuteState.
  973.  
  974.   if ParseState.TokenType ~== "/*EOF*/" then return 0
  975.   ParseState.CurrentToken = "/*EOF*/"
  976. return 1                                /* TRUE (1) means matched */
  977.  
  978.  
  979. /* Issue a token tracing message */
  980. TokenTrace: procedure expose LexState. ParseState. ExecuteState.
  981.   if ParseState.TokenTrace ,
  982.     then say right("",ParseState.Indent,'09'x)"GetToken Token=<"ParseState.CurrentToken"> Type =" ParseState.TokenType
  983. return
  984.  
  985. /* Issue a parse trace entered message */
  986. ParseTrace: procedure expose LexState. ParseState. ExecuteState.
  987.   if ParseState.ParseTrace then say right("",ParseState.Indent,'09'x)arg(1)
  988. return
  989.  
  990.  
  991. /* Issue a parse trace entered message */
  992. ParseTraceEntry: procedure expose LexState. ParseState. ExecuteState.
  993.   if ParseState.ParseTrace ,
  994.     then say right("",ParseState.Indent,'09'x)arg(1) "Entered"
  995.   ParseState.Indent = ParseState.Indent + 1
  996. return
  997.  
  998.  
  999. /* Issue a parse trace exited message */
  1000. ParseTraceExit: procedure expose LexState. ParseState. ExecuteState.
  1001.   ParseState.Indent = ParseState.Indent - 1
  1002.   if ParseState.ParseTrace ,
  1003.     then say right("",ParseState.Indent,'09'x)arg(1) "Exited"
  1004. return
  1005.  
  1006. /* Return next token from input stream, or '/*EOF*/' */
  1007. GetToken: procedure expose WsIn LexState. ParseState. ExecuteState.
  1008.  
  1009.   if ParseState.UnGetQueue ~== "" ,
  1010.     then do
  1011.            ParseState.CurrentToken = ParseState.UnGetQueue
  1012.            ParseState.UnGetQueue = ""
  1013.            ParseState.TokenType = ParseState.UnGetTypeQueue
  1014.            ParseState.UnGetTypeQueue = ""
  1015.            call TokenTrace()
  1016.            return
  1017.          end
  1018.  
  1019.   CurrentChar = GetChar()
  1020.   do while verify(CurrentChar,'090A0B0C0D20'x) = 0
  1021.     CurrentChar = GetChar()
  1022.   end
  1023.   if CurrentChar = '04'x ,
  1024.     then do
  1025.            ParseState.CurrentToken = "/*EOF*/"
  1026.            ParseState.TokenType    = "/*EOF*/"
  1027.            call TokenTrace()
  1028.            return
  1029.          end
  1030.  
  1031.   select;
  1032.     when CurrentChar == '"' ,
  1033.       then do
  1034.              ParseState.CurrentToken = ""
  1035.              ParseState.TokenType = "/*STRQQ*/"
  1036.  
  1037.              CurrentChar = GetChar()
  1038.              do while CurrentChar ~== '"' & CurrentChar ~== '04'x
  1039.                if CurrentChar == "\" ,
  1040.                  then do
  1041.                         CurrentChar = GetChar()
  1042.                         select
  1043.                           when CurrentChar == '04'x ,
  1044.                             then say "3 Digit octal string truncated by EOF"
  1045.                           when CurrentChar == '+' ,
  1046.                             then CurrentChar = ""
  1047.                           when CurrentChar == 'n' ,
  1048.                             then CurrentChar = '0a'x
  1049.                           when verify(CurrentChar,"01234567") = 0 ,
  1050.                             then do
  1051.                                    CharNumber = CurrentChar
  1052.                                    do i=1 to 2
  1053.                                       CurrentChar = GetChar()
  1054.                                       select;
  1055.                                         when CurrentChar == '04'x ,
  1056.                                           then say "3 Digit octal string truncated by EOF"
  1057.                                         when CurrentChar == '"' ,
  1058.                                           then say '3 Digit octal string truncated by "'
  1059.                                         otherwise
  1060.                                           if verify(CurrentChar,"01234567") ~= 0 ,
  1061.                                             then say "3 Digit octal string truncated by" CurrentChar
  1062.                                             else CharNumber = 8 * CharNumber + CurrentChar
  1063.                                       end
  1064.                                    end
  1065.                                    CurrentChar = d2c(CharNumber)
  1066.                                  end
  1067.                           otherwise
  1068.                             nop;
  1069.                         end
  1070.                       end
  1071.                else if CurrentChar == '0d'x ,
  1072.                   then do
  1073.                     CurrentChar = ""
  1074.                   end
  1075.                ParseState.CurrentToken = ParseState.CurrentToken || CurrentChar
  1076.                CurrentChar = GetChar()
  1077.              end
  1078.              if CurrentChar == '04'x ,
  1079.                then say 'Missing " from string (EOF hit).'
  1080.              call TokenTrace()
  1081.              return
  1082.            end
  1083.  
  1084.     when CurrentChar == "`" ,
  1085.       then do
  1086.              ParseState.CurrentToken = ""
  1087.              ParseState.TokenType = "/*STRTIC*/"
  1088.  
  1089.              CurrentChar = GetChar()
  1090.              do while CurrentChar ~== "`" & CurrentChar ~== '04'x
  1091.                ParseState.CurrentToken = ParseState.CurrentToken || CurrentChar
  1092.                CurrentChar = GetChar()
  1093.              end
  1094.              if CurrentChar == '04'x ,
  1095.                then say "Missing ` from string (EOF hit)."
  1096.              call TokenTrace()
  1097.              return
  1098.            end
  1099.  
  1100.     when verify(CurrentChar,"ABCDEFGHIJKLMNOPQRSTUVWXYZ_") = 0 ,
  1101.       then do
  1102.              ParseState.CurrentToken = CurrentChar
  1103.              ParseState.TokenType = "/*KEY*/"
  1104.  
  1105.              CurrentChar = GetChar()
  1106.              do while verify(CurrentChar,"ABCDEFGHIJKLMNOPQRSTUVWXYZ_") = 0
  1107.                ParseState.CurrentToken = ParseState.CurrentToken || CurrentChar
  1108.                CurrentChar = GetChar()
  1109.              end
  1110.              call UnGetChar(CurrentChar)
  1111.              call TokenTrace()
  1112.              return
  1113.            end;
  1114.  
  1115.     when verify(CurrentChar,"-0123456789") = 0 ,
  1116.       then do
  1117.              ParseState.CurrentToken = CurrentChar
  1118.              ParseState.TokenType = "/*NUM*/"
  1119.  
  1120.              CurrentChar = GetChar()
  1121.              do while verify(CurrentChar,"0123456789") = 0
  1122.                if CurrentChar == '04'x ,
  1123.                  then return ParseState.CurrentToken
  1124.                ParseState.CurrentToken = ParseState.CurrentToken || CurrentChar
  1125.                CurrentChar = GetChar()
  1126.              end
  1127.              call UnGetChar(CurrentChar)
  1128.              call TokenTrace()
  1129.              return
  1130.            end;
  1131.  
  1132.     otherwise
  1133.       do
  1134.         ParseState.CurrentToken = CurrentChar
  1135.         ParseState.TokenType = "/*OP*/"
  1136.         call TokenTrace()
  1137.         return
  1138.       end
  1139.   end;
  1140.  
  1141.   ParseState.CurrentToken       ="/*ERROR*/"
  1142.   ParseState.TokenType  ="/*ERROR*/"
  1143.         call TokenTrace()
  1144. return
  1145.  
  1146.  
  1147. /* Push back a single token onto the UnGetTokenQueue */
  1148. UnGetToken: procedure expose ParseState.
  1149.   if ParseState.TokenTrace ,
  1150.     then say right("",ParseState.Indent,'09'x)"UnGetToken=<"ParseState.CurrentToken"> Type ="ParseState.TokenType
  1151.   ParseState.UnGetQueue         = ParseState.CurrentToken
  1152.   ParseState.UnGetTypeQueue     = ParseState.TokenType
  1153. return
  1154.  
  1155.  
  1156. /* Returns a single character at every call;
  1157.  * At EOF, it then returns the single char EOT ('04'x) */
  1158. GetChar: procedure expose WsIn LexState.
  1159.  
  1160.   if length(LexState.UnGetQueue) > 0 ,
  1161.     then do
  1162.            ReturnChar = substr(LexState.UnGetQueue,1,1)
  1163.            LexState.UnGetQueue = delstr(LexState.UnGetQueue,1,1)
  1164.            return ReturnChar
  1165.          end
  1166.  
  1167.   if LexState.CurrentLine == "" ,
  1168.    | LexState.CurrentCol > length(LexState.CurrentLine) ,
  1169.    | LexState.CurrentCol <= 0,
  1170.     then do
  1171.            if eof(WsIn) ,
  1172.              then return '04'x
  1173.  
  1174.            do until LexState.CurrentLine ~== ""
  1175.              LexState.CurrentLine = readln(WsIn)
  1176.              LexState.LineNumber = LexState.LineNumber + 1
  1177.              if eof(WsIn) ,
  1178.                then return '04'x
  1179.              if LexState.List ,
  1180.                then say right(LexState.LineNumber,5," ") Lexstate.CurrentLine
  1181.            end
  1182.            LexState.CurrentCol = 1
  1183.          end
  1184.  
  1185.   CurrentChar = substr(LexState.CurrentLine, LexState.CurrentCol, 1)
  1186.   LexState.CurrentCol = LexState.CurrentCol + 1
  1187. return CurrentChar
  1188.  
  1189.  
  1190. /* Push back a single character onto the LexState.UnGetQueue */
  1191. UnGetChar: procedure expose LexState.
  1192.   LexState.UnGetQueue = arg(1) || LexState.UnGetQueue
  1193. return
  1194.  
  1195.  
  1196. /* Wait until Maple is idle,
  1197.  * then send a return to force it to start executing. */
  1198. SendReturn: procedure expose ExecuteState.
  1199.   if ~ExecuteState.Async ,
  1200.     then do
  1201.            do until MapleRC = 0
  1202.              "GetMapleStatus"
  1203.              MapleRC = RC
  1204.              address command "wait 3 secs"
  1205.            end
  1206.          end
  1207.   "SendReturn"
  1208. return
  1209.